package com.cskaoyan.javase.oop1._2reference;

/**
 * 我们第一次认识和了解引用数据类型是在数组这一章节
 * 我们通过JVM内存模型图和数组的初始化过程，知道：
 *
 * 一个引用数据类型变量，分为两个部分：
 *      1.在栈上创建引用，它是一个局部变量。
 *      2.在堆上开辟空间，创建对象。
 * 栈上的引用通过存储堆上对象的地址和对象产生联系。
 * 对象是引用数据类型的实质，但我们只能通过栈上引用间接访问堆上对象。
 * 现在，我们已经学习过对象与类的知识点了，是时候进一步或者换一个角度去了解引用数据类型了。
 *
 * 像数组那样理解引用数据类型，虽然看到了引用数据类型的实质
 * 但也把基本数据类型和引用数据类型完全割裂了。
 * 这两种数据类型当然不可能是完全没有关系的了！
 * 所以，我们需要让它们重新产生联系起来！
 *
 * 先回顾一下，在Java基础语法部分，我们给出的数据类型的概念/定义：
 *      数据类型： 表示的是一组数据的集合，和基于该数据集合的一组合法操作。
 *      数据类型 = 数据 + 操作
 * 这个定义套在基本数据类型上，实在再合适不过了。
 * 比如int类型，它的取值范围是固定的，有限的，能够做的操作（加减乘除等）也是被限制的。
 * 那么这个定义能不能套在引用数据类型中呢？能否用数据类型的概念来统一基本数据类型和引用数据类型呢？
 * 当然是可以的.
 * 接下来我们需要分析一下，这个问题。
 *
 * 在上一节类的定义中，类中的成员包括：
 *      1.成员变量
 *      2.成员方法
 * 成员变量本质上就是数据，成员方法本质上就是操作
 * 那么假设做以下类比：
 *      1.数据的集合： 类中成员变量的集合
 *      2.操作的集合： 类中成员方法的集合
 * 于是，就可以做出以下总结(重点)：
 *      一个类的定义，实际上就是定义了一种全新的数据类型，一种自定义的数据类型。
 *      定义类时,定义的成员变量就是定义数据
 *      定义类时,定义的成员方法就是定义操作
 *      这种完全不同于基本数据类型的数据类型，我们称之为"引用数据类型"。
 *      注：当然引用数据类型不仅仅包括类，但大体上上述说法是没问题的。
 *
 * 引用数据类型和基本数据类型的不同点(重点):
 *      当我们在程序中使用一个基本数据类型时
 *      由于基本数据类型是JVM当中已经预先定义好的（所以基本数据类型叫"内置数据类型"）
 *      JVM可以清楚的知道这个基本数据类型变量在内存中的存储方式（占用空间大小、结构等等）
 *      JVM能够正常开辟空间，正常给变量初始化赋值。
 *
 * 但是类这种引用数据类型，并不是内置数据类型，而是我们自定义的数据类型。
 * 现在我们要求JVM根据一个类来创建它的对象，要让JVM帮助我们开辟空间创建引用和对象
 * JVM怎么知道到底要创建什么呢？难道它未卜先知吗？
 *
 * 显然是不可能的，某个类在一开始并不被JVM"认识"——它不知道类中有什么，必然不可能做任何操作。
 * 所以在对某个类做任何操作之前，都需要让JVM来"认识,了解"这个类型。
 * 在Java中，把JVM"认识,了解"一个引用数据类型的过程，称之为"类加载"。
 *
 * 关于类加载,我们要清除以下:
 *      1.类加载的具体过程，我们后面会详细学习。这里我们先不用了解它的详细过程了。
 *      2.目前这个阶段,我们仅需要知道:
 *          (重点)类加载是通过把某个类的二进制字节码文件（class文件）通过I/O流的形式
 *              读取进JVM内存中的方法区实现的。
 *      3.类加载的特点是什么?
 *              a.类加载是通过I/O流的形式开始的
 *                  I/O流: 将数据从外存中读取进内存,以及从内存中写入外存,统称I/O
 *                      比如从U盘读取数据/写入数据,就是典型的I/O
 *                      I/O的最大问题是效率低
 *                  所以JVM进行类加载,最大的问题也是效率低(和Java程序的运行本身相比)
 *
 *              b.既然效率低,类加载是越多越好,还是越少越好?
 *                  启动一个Java程序,可能会用到很多类,那么这些类的类加载是用到了再类加载,还是启动程序时就全部类加载?
 *                  当然是越少越好,而且某个类的类加载必须等到用到该类时才会进行.
 *                  于是类加载的这两个特点,就可以总结成:
 *                  类加载是"懒加载"的.(重点)
 *                  Java程序中的某个类,必须等到确定要使用它时,才会进行类加载.
 *                  在Java中,把某个类"必须要类加载,不类加载程序无法继续执行的场景"
 *                  称之为"类加载的时机"(重点)
 *
 *               c.类加载的时机,有很多,后续慢慢学习
 *                  但实际上你已经知道了两种类加载的时机:
 *                      1.启动main方法,触发装有main方法类的类加载
 *                      2.new对象,一旦创建某个类的对象,就必须类加载它
 *                  以上类加载的时机,是先类加载,还是先执行它们?
 *                      肯定是先类加载,类加载完毕后再执行它们
 *
 *              d.某个类,在程序的一次运行中,类加载有几次?
 *                  一个类要么不类加载,要么最多类加载一次(某一次程序运行过程中)
 *                  这意味着,程序运行碰到了类加载的时机,如果该类已经类加载了,也不会再次类加载了!
 *
 * @since 09:44
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    // 先类加载Demo,类加载结束后,再启动main方法
    public static void main(String[] args) {
        // new Teacher对象,先类加载Teacher,再new对象
        Teacher t = new Teacher();

        /*
            newDemo对象,会类加载它吗?
            不会,因为该类的类加载已经通过启动main方法触发了
            不会再次类加载!
          */
        Demo d = new Demo();
    }
}
// 程序的执行和类A没有关系,所以它不类加载
class A{}
class Teacher {
    /*
        引用数据类型成员变量
        在Teacher对象当中存储的是引用数据类型变量name的地址/引用
      */
    String name;
}